home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / bsddb / __init__.py next >
Encoding:
Text File  |  2006-06-20  |  13.7 KB  |  398 lines

  1. #----------------------------------------------------------------------
  2. #  Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA
  3. #  and Andrew Kuchling. All rights reserved.
  4. #
  5. #  Redistribution and use in source and binary forms, with or without
  6. #  modification, are permitted provided that the following conditions are
  7. #  met:
  8. #
  9. #    o Redistributions of source code must retain the above copyright
  10. #      notice, this list of conditions, and the disclaimer that follows.
  11. #
  12. #    o Redistributions in binary form must reproduce the above copyright
  13. #      notice, this list of conditions, and the following disclaimer in
  14. #      the documentation and/or other materials provided with the
  15. #      distribution.
  16. #
  17. #    o Neither the name of Digital Creations nor the names of its
  18. #      contributors may be used to endorse or promote products derived
  19. #      from this software without specific prior written permission.
  20. #
  21. #  THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
  22. #  IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  23. #  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  24. #  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL
  25. #  CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. #  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. #  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. #  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29. #  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  30. #  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  31. #  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  32. #  DAMAGE.
  33. #----------------------------------------------------------------------
  34.  
  35.  
  36. """Support for BerkeleyDB 3.3 through 4.4 with a simple interface.
  37.  
  38. For the full featured object oriented interface use the bsddb.db module
  39. instead.  It mirrors the Sleepycat BerkeleyDB C API.
  40. """
  41.  
  42. try:
  43.     if __name__ == 'bsddb3':
  44.         # import _pybsddb binary as it should be the more recent version from
  45.         # a standalone pybsddb addon package than the version included with
  46.         # python as bsddb._bsddb.
  47.         import _pybsddb
  48.         _bsddb = _pybsddb
  49.         from bsddb3.dbutils import DeadlockWrap as _DeadlockWrap
  50.     else:
  51.         import _bsddb
  52.         from bsddb.dbutils import DeadlockWrap as _DeadlockWrap
  53. except ImportError:
  54.     # Remove ourselves from sys.modules
  55.     import sys
  56.     del sys.modules[__name__]
  57.     raise
  58.  
  59. # bsddb3 calls it db, but provide _db for backwards compatibility
  60. db = _db = _bsddb
  61. __version__ = db.__version__
  62.  
  63. error = db.DBError  # So bsddb.error will mean something...
  64.  
  65. #----------------------------------------------------------------------
  66.  
  67. import sys, os
  68.  
  69. # for backwards compatibility with python versions older than 2.3, the
  70. # iterator interface is dynamically defined and added using a mixin
  71. # class.  old python can't tokenize it due to the yield keyword.
  72. if sys.version >= '2.3':
  73.     import UserDict
  74.     from weakref import ref
  75.     exec """
  76. class _iter_mixin(UserDict.DictMixin):
  77.     def _make_iter_cursor(self):
  78.         cur = _DeadlockWrap(self.db.cursor)
  79.         key = id(cur)
  80.         self._cursor_refs[key] = ref(cur, self._gen_cref_cleaner(key))
  81.         return cur
  82.  
  83.     def _gen_cref_cleaner(self, key):
  84.         # use generate the function for the weakref callback here
  85.         # to ensure that we do not hold a strict reference to cur
  86.         # in the callback.
  87.         return lambda ref: self._cursor_refs.pop(key, None)
  88.  
  89.     def __iter__(self):
  90.         try:
  91.             cur = self._make_iter_cursor()
  92.  
  93.             # FIXME-20031102-greg: race condition.  cursor could
  94.             # be closed by another thread before this call.
  95.  
  96.             # since we're only returning keys, we call the cursor
  97.             # methods with flags=0, dlen=0, dofs=0
  98.             key = _DeadlockWrap(cur.first, 0,0,0)[0]
  99.             yield key
  100.  
  101.             next = cur.next
  102.             while 1:
  103.                 try:
  104.                     key = _DeadlockWrap(next, 0,0,0)[0]
  105.                     yield key
  106.                 except _bsddb.DBCursorClosedError:
  107.                     cur = self._make_iter_cursor()
  108.                     # FIXME-20031101-greg: race condition.  cursor could
  109.                     # be closed by another thread before this call.
  110.                     _DeadlockWrap(cur.set, key,0,0,0)
  111.                     next = cur.next
  112.         except _bsddb.DBNotFoundError:
  113.             return
  114.         except _bsddb.DBCursorClosedError:
  115.             # the database was modified during iteration.  abort.
  116.             return
  117.  
  118.     def iteritems(self):
  119.         if not self.db:
  120.             return
  121.         try:
  122.             cur = self._make_iter_cursor()
  123.  
  124.             # FIXME-20031102-greg: race condition.  cursor could
  125.             # be closed by another thread before this call.
  126.  
  127.             kv = _DeadlockWrap(cur.first)
  128.             key = kv[0]
  129.             yield kv
  130.  
  131.             next = cur.next
  132.             while 1:
  133.                 try:
  134.                     kv = _DeadlockWrap(next)
  135.                     key = kv[0]
  136.                     yield kv
  137.                 except _bsddb.DBCursorClosedError:
  138.                     cur = self._make_iter_cursor()
  139.                     # FIXME-20031101-greg: race condition.  cursor could
  140.                     # be closed by another thread before this call.
  141.                     _DeadlockWrap(cur.set, key,0,0,0)
  142.                     next = cur.next
  143.         except _bsddb.DBNotFoundError:
  144.             return
  145.         except _bsddb.DBCursorClosedError:
  146.             # the database was modified during iteration.  abort.
  147.             return
  148. """
  149. else:
  150.     class _iter_mixin: pass
  151.  
  152.  
  153. class _DBWithCursor(_iter_mixin):
  154.     """
  155.     A simple wrapper around DB that makes it look like the bsddbobject in
  156.     the old module.  It uses a cursor as needed to provide DB traversal.
  157.     """
  158.     def __init__(self, db):
  159.         self.db = db
  160.         self.db.set_get_returns_none(0)
  161.  
  162.         # FIXME-20031101-greg: I believe there is still the potential
  163.         # for deadlocks in a multithreaded environment if someone
  164.         # attempts to use the any of the cursor interfaces in one
  165.         # thread while doing a put or delete in another thread.  The
  166.         # reason is that _checkCursor and _closeCursors are not atomic
  167.         # operations.  Doing our own locking around self.dbc,
  168.         # self.saved_dbc_key and self._cursor_refs could prevent this.
  169.         # TODO: A test case demonstrating the problem needs to be written.
  170.  
  171.         # self.dbc is a DBCursor object used to implement the
  172.         # first/next/previous/last/set_location methods.
  173.         self.dbc = None
  174.         self.saved_dbc_key = None
  175.  
  176.         # a collection of all DBCursor objects currently allocated
  177.         # by the _iter_mixin interface.
  178.         self._cursor_refs = {}
  179.  
  180.     def __del__(self):
  181.         self.close()
  182.  
  183.     def _checkCursor(self):
  184.         if self.dbc is None:
  185.             self.dbc = _DeadlockWrap(self.db.cursor)
  186.             if self.saved_dbc_key is not None:
  187.                 _DeadlockWrap(self.dbc.set, self.saved_dbc_key)
  188.                 self.saved_dbc_key = None
  189.  
  190.     # This method is needed for all non-cursor DB calls to avoid
  191.     # BerkeleyDB deadlocks (due to being opened with DB_INIT_LOCK
  192.     # and DB_THREAD to be thread safe) when intermixing database
  193.     # operations that use the cursor internally with those that don't.
  194.     def _closeCursors(self, save=1):
  195.         if self.dbc:
  196.             c = self.dbc
  197.             self.dbc = None
  198.             if save:
  199.                 try:
  200.                     self.saved_dbc_key = _DeadlockWrap(c.current, 0,0,0)[0]
  201.                 except db.DBError:
  202.                     pass
  203.             _DeadlockWrap(c.close)
  204.             del c
  205.         for cref in self._cursor_refs.values():
  206.             c = cref()
  207.             if c is not None:
  208.                 _DeadlockWrap(c.close)
  209.  
  210.     def _checkOpen(self):
  211.         if self.db is None:
  212.             raise error, "BSDDB object has already been closed"
  213.  
  214.     def isOpen(self):
  215.         return self.db is not None
  216.  
  217.     def __len__(self):
  218.         self._checkOpen()
  219.         return _DeadlockWrap(lambda: len(self.db))  # len(self.db)
  220.  
  221.     def __getitem__(self, key):
  222.         self._checkOpen()
  223.         return _DeadlockWrap(lambda: self.db[key])  # self.db[key]
  224.  
  225.     def __setitem__(self, key, value):
  226.         self._checkOpen()
  227.         self._closeCursors()
  228.         def wrapF():
  229.             self.db[key] = value
  230.         _DeadlockWrap(wrapF)  # self.db[key] = value
  231.  
  232.     def __delitem__(self, key):
  233.         self._checkOpen()
  234.         self._closeCursors()
  235.         def wrapF():
  236.             del self.db[key]
  237.         _DeadlockWrap(wrapF)  # del self.db[key]
  238.  
  239.     def close(self):
  240.         self._closeCursors(save=0)
  241.         if self.dbc is not None:
  242.             _DeadlockWrap(self.dbc.close)
  243.         v = 0
  244.         if self.db is not None:
  245.             v = _DeadlockWrap(self.db.close)
  246.         self.dbc = None
  247.         self.db = None
  248.         return v
  249.  
  250.     def keys(self):
  251.         self._checkOpen()
  252.         return _DeadlockWrap(self.db.keys)
  253.  
  254.     def has_key(self, key):
  255.         self._checkOpen()
  256.         return _DeadlockWrap(self.db.has_key, key)
  257.  
  258.     def set_location(self, key):
  259.         self._checkOpen()
  260.         self._checkCursor()
  261.         return _DeadlockWrap(self.dbc.set_range, key)
  262.  
  263.     def next(self):
  264.         self._checkOpen()
  265.         self._checkCursor()
  266.         rv = _DeadlockWrap(self.dbc.next)
  267.         return rv
  268.  
  269.     def previous(self):
  270.         self._checkOpen()
  271.         self._checkCursor()
  272.         rv = _DeadlockWrap(self.dbc.prev)
  273.         return rv
  274.  
  275.     def first(self):
  276.         self._checkOpen()
  277.         self._checkCursor()
  278.         rv = _DeadlockWrap(self.dbc.first)
  279.         return rv
  280.  
  281.     def last(self):
  282.         self._checkOpen()
  283.         self._checkCursor()
  284.         rv = _DeadlockWrap(self.dbc.last)
  285.         return rv
  286.  
  287.     def sync(self):
  288.         self._checkOpen()
  289.         return _DeadlockWrap(self.db.sync)
  290.  
  291.  
  292. #----------------------------------------------------------------------
  293. # Compatibility object factory functions
  294.  
  295. def hashopen(file, flag='c', mode=0666, pgsize=None, ffactor=None, nelem=None,
  296.             cachesize=None, lorder=None, hflags=0):
  297.  
  298.     flags = _checkflag(flag, file)
  299.     e = _openDBEnv(cachesize)
  300.     d = db.DB(e)
  301.     d.set_flags(hflags)
  302.     if pgsize is not None:    d.set_pagesize(pgsize)
  303.     if lorder is not None:    d.set_lorder(lorder)
  304.     if ffactor is not None:   d.set_h_ffactor(ffactor)
  305.     if nelem is not None:     d.set_h_nelem(nelem)
  306.     d.open(file, db.DB_HASH, flags, mode)
  307.     return _DBWithCursor(d)
  308.  
  309. #----------------------------------------------------------------------
  310.  
  311. def btopen(file, flag='c', mode=0666,
  312.             btflags=0, cachesize=None, maxkeypage=None, minkeypage=None,
  313.             pgsize=None, lorder=None):
  314.  
  315.     flags = _checkflag(flag, file)
  316.     e = _openDBEnv(cachesize)
  317.     d = db.DB(e)
  318.     if pgsize is not None: d.set_pagesize(pgsize)
  319.     if lorder is not None: d.set_lorder(lorder)
  320.     d.set_flags(btflags)
  321.     if minkeypage is not None: d.set_bt_minkey(minkeypage)
  322.     if maxkeypage is not None: d.set_bt_maxkey(maxkeypage)
  323.     d.open(file, db.DB_BTREE, flags, mode)
  324.     return _DBWithCursor(d)
  325.  
  326. #----------------------------------------------------------------------
  327.  
  328.  
  329. def rnopen(file, flag='c', mode=0666,
  330.             rnflags=0, cachesize=None, pgsize=None, lorder=None,
  331.             rlen=None, delim=None, source=None, pad=None):
  332.  
  333.     flags = _checkflag(flag, file)
  334.     e = _openDBEnv(cachesize)
  335.     d = db.DB(e)
  336.     if pgsize is not None: d.set_pagesize(pgsize)
  337.     if lorder is not None: d.set_lorder(lorder)
  338.     d.set_flags(rnflags)
  339.     if delim is not None: d.set_re_delim(delim)
  340.     if rlen is not None: d.set_re_len(rlen)
  341.     if source is not None: d.set_re_source(source)
  342.     if pad is not None: d.set_re_pad(pad)
  343.     d.open(file, db.DB_RECNO, flags, mode)
  344.     return _DBWithCursor(d)
  345.  
  346. #----------------------------------------------------------------------
  347.  
  348. def _openDBEnv(cachesize):
  349.     e = db.DBEnv()
  350.     if cachesize is not None:
  351.         if cachesize >= 20480:
  352.             e.set_cachesize(0, cachesize)
  353.         else:
  354.             raise error, "cachesize must be >= 20480"
  355.     e.set_lk_detect(db.DB_LOCK_DEFAULT)
  356.     e.open('.', db.DB_PRIVATE | db.DB_CREATE | db.DB_THREAD | db.DB_INIT_LOCK | db.DB_INIT_MPOOL)
  357.     return e
  358.  
  359. def _checkflag(flag, file):
  360.     if flag == 'r':
  361.         flags = db.DB_RDONLY
  362.     elif flag == 'rw':
  363.         flags = 0
  364.     elif flag == 'w':
  365.         flags =  db.DB_CREATE
  366.     elif flag == 'c':
  367.         flags =  db.DB_CREATE
  368.     elif flag == 'n':
  369.         flags = db.DB_CREATE
  370.         #flags = db.DB_CREATE | db.DB_TRUNCATE
  371.         # we used db.DB_TRUNCATE flag for this before but BerkeleyDB
  372.         # 4.2.52 changed to disallowed truncate with txn environments.
  373.         if file is not None and os.path.isfile(file):
  374.             os.unlink(file)
  375.     else:
  376.         raise error, "flags should be one of 'r', 'w', 'c' or 'n'"
  377.     return flags | db.DB_THREAD
  378.  
  379. #----------------------------------------------------------------------
  380.  
  381.  
  382. # This is a silly little hack that allows apps to continue to use the
  383. # DB_THREAD flag even on systems without threads without freaking out
  384. # BerkeleyDB.
  385. #
  386. # This assumes that if Python was built with thread support then
  387. # BerkeleyDB was too.
  388.  
  389. try:
  390.     import thread
  391.     del thread
  392.     if db.version() < (3, 3, 0):
  393.         db.DB_THREAD = 0
  394. except ImportError:
  395.     db.DB_THREAD = 0
  396.  
  397. #----------------------------------------------------------------------
  398.